
package analiseSintatica.Regras.Tipos;

import AnaliseLexicaFinal.EstruturaDeDados.LinkToken;
import AnaliseLexicaFinal.EstruturaDeDados.Token;
import analiseSintatica.ErroSintaticoException;
import analiseSintatica.Regras.DeclaracoesIniciais.RegraDeclaracao;
import analiseSintatica.Regras.Regra;
import analiseSintatica.estruturadados.ErroSintatico;
import analiseSintatica.estruturadados.NoArvore;

import java.util.LinkedList;

/**
 *
 * @author Edney
 */
public class RegraStruct extends Regra {

    protected static Regra instancia;

    protected String estrutura = "<struct> ::= struct '{' {<declaracao>}+ '}'";

    /**
     * Construtor privado necessario ao singleton
     */
    private RegraStruct() {
    }

    /**
     * Retorna a unica instancia dessa classe.
     * @return
     */
    public static RegraStruct getInstance() {
        if (instancia == null) {
            instancia = new RegraStruct();
        }
        return (RegraStruct) instancia;
    }

    @Override
    public NoArvore analisar(LinkedList<LinkToken> listaTokens) throws ErroSintaticoException {

        ErroSintaticoException erros = new ErroSintaticoException();
        
        NoArvore naoterminalStruct = new NoArvore("<struct>", false);

        naoterminalStruct.adicionaFilho(reconheceToken(listaTokens, "struct",estrutura));

        try{
            naoterminalStruct.adicionaFilho(reconheceLexema(listaTokens, "delimitador","{",estrutura));
        }

        catch(ErroSintaticoException e){

            ErroSintatico erro = e.getErros();
			erro.setCorreto(estrutura);
			erros.addErros(erro);

            LinkedList<String> sincronizacao = RegraDeclaracao.getInstance().getPrimeiro();
			LinkedList<String> abrechave = new LinkedList<String>();
			abrechave.add("{");
			sincronizacao = getUniao(sincronizacao, abrechave);

            while(!listaContem(sincronizacao, listaTokens.getFirst())){
				erros.addErros("Token "+listaTokens.getFirst().getToken()+" nao permitido", estrutura, listaTokens.getFirst().getLinha());
				listaTokens.removeFirst();
			}
			if (listaTokens.getFirst().getToken().equals("delimitador") && listaTokens.getFirst().getLexema().equals("{"))
				listaTokens.removeFirst();

        }

        do {
            try{
            
            naoterminalStruct.adicionaFilho(RegraDeclaracao.getInstance().analisar(listaTokens));

            }
            catch(ErroSintaticoException e){

                while(e.size() != 0)
				erros.addErros(e.getErros());


            }
        }while(RegraDeclaracao.getInstance().getPrimeiro().contains(listaTokens.getFirst().getToken())||
                RegraDeclaracao.getInstance().getPrimeiro().contains(listaTokens.getFirst().getLexema()));
           
        try{

            naoterminalStruct.adicionaFilho(reconheceLexema(listaTokens, "delimitador","}",estrutura));

        }
        catch(ErroSintaticoException e){

            ErroSintatico erro = e.getErros();
			erro.setCorreto(estrutura);
			erros.addErros(erro);

            LinkedList<String> fechachave = new LinkedList<String>();
			fechachave.add("{");
            fechachave.add(";");
			

            while(!listaContem(fechachave, listaTokens.getFirst())){
				erros.addErros("Token "+listaTokens.getFirst().getToken()+" nao permitido", estrutura, listaTokens.getFirst().getLinha());
				listaTokens.removeFirst();
			}
			if (listaTokens.getFirst().getToken().equals("delimitador") && listaTokens.getFirst().getLexema().equals("}"))
				listaTokens.removeFirst();


        }
         System.out.println("Terminei Regra Struct");
        return naoterminalStruct;

    }


    @Override
    protected void setPrimeiro() {
        primeiro.add("struct");
    }

    @Override
    protected void setSeguinte() {
        seguinte.add("identificador");
    }

}
